package com.entertainment.ticketing.service;

import com.entertainment.ticketing.dto.CreateOrderRequest;
import com.entertainment.ticketing.dto.OrderItemDTO;
import com.entertainment.ticketing.dto.OrderResponse;
import com.entertainment.ticketing.entity.EventInfo;
import com.entertainment.ticketing.entity.OrderInfo;
import com.entertainment.ticketing.entity.OrderItem;
import com.entertainment.ticketing.entity.TicketInfo;
import com.entertainment.ticketing.entity.UserInfo;
import com.entertainment.ticketing.repository.EventInfoRepository;
import com.entertainment.ticketing.repository.OrderInfoRepository;
import com.entertainment.ticketing.repository.OrderItemRepository;
import com.entertainment.ticketing.repository.TicketInfoRepository;
import com.entertainment.ticketing.repository.UserInfoRepository;
import org.springframework.http.HttpStatus;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

import com.entertainment.ticketing.dto.PageResponse;

@Service
public class OrderService {
    private final OrderInfoRepository orderRepo;
    private final OrderItemRepository itemRepo;
    private final TicketInfoRepository ticketRepo;
    private final UserInfoRepository userRepo;
    private final EventInfoRepository eventRepo;

    public OrderService(OrderInfoRepository orderRepo, OrderItemRepository itemRepo,
                        TicketInfoRepository ticketRepo, UserInfoRepository userRepo,
                        EventInfoRepository eventRepo) {
        this.orderRepo = orderRepo;
        this.itemRepo = itemRepo;
        this.ticketRepo = ticketRepo;
        this.userRepo = userRepo;
        this.eventRepo = eventRepo;
    }

    @Transactional
    public OrderResponse createOrder(CreateOrderRequest req) {
        return createOrder(req, null);
    }

    @Transactional
    public OrderResponse createOrder(CreateOrderRequest req, String idempotencyKey) {
        UserInfo user = userRepo.findById(req.getUserId())
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "用户不存在"));
        EventInfo event = eventRepo.findById(req.getEventId())
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "演出不存在"));

        if (idempotencyKey != null && !idempotencyKey.isBlank()) {
            java.util.Optional<OrderInfo> existed = orderRepo.findByRemark(idempotencyKey);
            if (existed.isPresent()) {
                OrderInfo existedOrder = existed.get();
                java.util.List<OrderItem> existedItems = itemRepo.findByOrder_Id(existedOrder.getId());
                return toResponse(existedOrder, existedItems);
            }
        }
        List<TicketInfo> tickets = ticketRepo.findByIdInForUpdate(req.getTicketIds());
        if (tickets.size() != req.getTicketIds().size()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "选择的票有不存在的条目");
        }
        for (TicketInfo t : tickets) {
            if (!t.getEvent().getId().equals(event.getId())) {
                throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "票与演出不匹配");
            }
            if (t.getStatus() == null || t.getStatus() != 1) {
                throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "包含不可售或已售的票");
            }
        }
        BigDecimal total = tickets.stream()
                .map(TicketInfo::getPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        int count = tickets.size();

        String orderNo = generateOrderNo();
        while (orderRepo.existsByOrderNo(orderNo)) {
            orderNo = generateOrderNo();
        }

        OrderInfo order = new OrderInfo();
        order.setOrderNo(orderNo);
        order.setUser(user);
        order.setEvent(event);
        order.setTotalAmount(total);
        order.setTicketCount(count);
        order.setStatus((byte)(req.getPaymentMethod() != null && !req.getPaymentMethod().isBlank() ? 2 : 1));
        order.setPaymentMethod(req.getPaymentMethod());
        order.setPaymentTime(order.getStatus() == 2 ? LocalDateTime.now() : null);
        order.setContactName(req.getContactName());
        order.setContactPhone(req.getContactPhone());
        order.setContactEmail(req.getContactEmail());
        order.setRemark(idempotencyKey);

        OrderInfo savedOrder = orderRepo.save(order);

        List<OrderItem> items = new ArrayList<>();
        for (TicketInfo t : tickets) {
            OrderItem item = new OrderItem();
            item.setOrder(savedOrder);
            item.setTicket(t);
            item.setPrice(t.getPrice());
            items.add(item);
        }
        itemRepo.saveAll(items);

        // 更新票状态与演出可用座位
        for (TicketInfo t : tickets) {
            t.setStatus((byte)2); // 已售
        }
        ticketRepo.saveAll(tickets);
        event.setAvailableSeats(Math.max(0, event.getAvailableSeats() - count));
        eventRepo.save(event);

        return toResponse(savedOrder, items);
    }

    public OrderResponse getByOrderNo(String orderNo) {
        OrderInfo order = orderRepo.findByOrderNo(orderNo)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "订单不存在"));
        List<OrderItem> items = itemRepo.findByOrder_Id(order.getId());
        return toResponse(order, items);
    }

    @Transactional
    public OrderResponse cancelOrder(String orderNo) {
        OrderInfo order = orderRepo.findByOrderNo(orderNo)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "订单不存在"));
        if (order.getStatus() == null) {
            order.setStatus((byte)1);
        }
        if (order.getStatus() == 3) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "订单已取消");
        }
        if (order.getStatus() == 2) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "已支付订单不可取消");
        }

        // 回滚票状态与演出可用座位
        List<OrderItem> items = itemRepo.findByOrder_Id(order.getId());
        int count = items.size();
        List<TicketInfo> tickets = items.stream().map(OrderItem::getTicket).collect(java.util.stream.Collectors.toList());
        for (TicketInfo t : tickets) {
            t.setStatus((byte)1); // 设为可售
        }
        ticketRepo.saveAll(tickets);
        EventInfo event = order.getEvent();
        event.setAvailableSeats(event.getAvailableSeats() + count);
        eventRepo.save(event);

        // 更新订单状态
        order.setStatus((byte)3); // 已取消
        OrderInfo saved = orderRepo.save(order);
        return toResponse(saved, items);
    }

    @Transactional
    public OrderResponse payOrder(String orderNo) {
        OrderInfo order = orderRepo.findByOrderNo(orderNo)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "订单不存在"));
        if (order.getStatus() == null) {
            order.setStatus((byte)1);
        }
        if (order.getStatus() == 2) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "订单已支付");
        }
        if (order.getStatus() == 3) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "已取消订单不可支付");
        }
        order.setStatus((byte)2);
        order.setPaymentMethod(order.getPaymentMethod() != null ? order.getPaymentMethod() : "ALIPAY");
        order.setPaymentTime(LocalDateTime.now());
        OrderInfo saved = orderRepo.save(order);
        List<OrderItem> items = itemRepo.findByOrder_Id(order.getId());
        return toResponse(saved, items);
    }

    public java.util.List<OrderResponse> listByUsername(String username) {
        java.util.List<OrderInfo> orders = orderRepo.findByUser_UsernameOrderByCreatedAtDesc(username);
        java.util.List<OrderResponse> responses = new java.util.ArrayList<>();
        for (OrderInfo order : orders) {
            java.util.List<OrderItem> items = itemRepo.findByOrder_Id(order.getId());
            responses.add(toResponse(order, items));
        }
        return responses;
    }

    private OrderInfo findByIdOrOrderNo(String idOrOrderNo) {
        if (idOrOrderNo == null || idOrOrderNo.isBlank()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "参数无效");
        }
        try {
            Long id = Long.valueOf(idOrOrderNo);
            return orderRepo.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "订单不存在"));
        } catch (NumberFormatException e) {
            return orderRepo.findByOrderNo(idOrOrderNo).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "订单不存在"));
        }
    }

    @Transactional
    public OrderResponse updateStatusByAdmin(String idOrOrderNo, Byte status) {
        OrderInfo order = findByIdOrOrderNo(idOrOrderNo);
        if (status == null) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "状态不能为空");
        }
        if (status == 2) {
            return payOrder(order.getOrderNo());
        } else if (status == 3) {
            // 管理员设置取消：若已支付，则进行退款模拟；否则走普通取消
            if (order.getStatus() != null && order.getStatus() == 2) {
                return refundPaidOrder(order.getOrderNo());
            }
            return cancelOrder(order.getOrderNo());
        } else if (status == 4) {
            // 显式退款
            return refundPaidOrder(order.getOrderNo());
        } else {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "仅支持设置为已支付/已取消/已退款");
        }
    }

    /**
     * 管理端：订单分页搜索
     */
    public PageResponse<OrderResponse> search(
            String keyword,
            Byte status,
            Long userId,
            Long eventId,
            int page,
            int size,
            String sortBy,
            Sort.Direction order
    ) {
        Specification<OrderInfo> spec = Specification.where(null);

        if (keyword != null && !keyword.isBlank()) {
            String kw = "%" + keyword.trim().toLowerCase() + "%";
            spec = spec.and((root, query, cb) -> cb.or(
                    cb.like(cb.lower(root.get("orderNo")), kw),
                    cb.like(cb.lower(root.get("contactName")), kw),
                    cb.like(cb.lower(root.get("contactPhone")), kw),
                    cb.like(cb.lower(root.get("contactEmail")), kw)
            ));
        }
        if (status != null) {
            spec = spec.and((root, query, cb) -> cb.equal(root.get("status"), status));
        }
        if (userId != null) {
            spec = spec.and((root, query, cb) -> cb.equal(root.get("user").get("id"), userId));
        }
        if (eventId != null) {
            spec = spec.and((root, query, cb) -> cb.equal(root.get("event").get("id"), eventId));
        }

        java.util.List<String> allowedSorts = java.util.List.of("createdAt", "status", "totalAmount");
        String safeSortBy = allowedSorts.contains(sortBy) ? sortBy : "createdAt";
        int safePage = Math.max(0, page);
        int safeSize = Math.min(Math.max(1, size), 100);
        Pageable pageable = PageRequest.of(safePage, safeSize, Sort.by(order, safeSortBy));

        Page<OrderInfo> pageResult = orderRepo.findAll(spec, pageable);
        java.util.List<OrderResponse> content = new java.util.ArrayList<>();
        for (OrderInfo orderInfo : pageResult.getContent()) {
            java.util.List<OrderItem> items = itemRepo.findByOrder_Id(orderInfo.getId());
            content.add(toResponse(orderInfo, items));
        }
        return new PageResponse<>(
                content,
                pageResult.getNumber(),
                pageResult.getSize(),
                pageResult.getTotalElements(),
                pageResult.getTotalPages(),
                safeSortBy,
                order.name()
        );
    }

    @Transactional
    public OrderResponse refundPaidOrder(String orderNo) {
        OrderInfo order = orderRepo.findByOrderNo(orderNo)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "订单不存在"));
        if (order.getStatus() == null || order.getStatus() != 2) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "仅已支付订单可退款");
        }
        // 回滚票状态与演出可用座位
        List<OrderItem> items = itemRepo.findByOrder_Id(order.getId());
        int count = items.size();
        List<TicketInfo> tickets = items.stream().map(OrderItem::getTicket).collect(java.util.stream.Collectors.toList());
        for (TicketInfo t : tickets) {
            t.setStatus((byte)1); // 设为可售
        }
        ticketRepo.saveAll(tickets);
        EventInfo event = order.getEvent();
        event.setAvailableSeats(event.getAvailableSeats() + count);
        eventRepo.save(event);

        // 更新订单状态为已退款
        order.setStatus((byte)4);
        OrderInfo saved = orderRepo.save(order);
        return toResponse(saved, items);
    }

    @Transactional
    public java.util.List<OrderResponse> batchRefundPaidOrders(java.util.List<String> idsOrOrderNos) {
        java.util.List<OrderResponse> results = new java.util.ArrayList<>();
        if (idsOrOrderNos == null || idsOrOrderNos.isEmpty()) {
            return results;
        }
        for (String idOrNo : idsOrOrderNos) {
            try {
                OrderInfo order = findByIdOrOrderNo(idOrNo);
                if (order.getStatus() != null && order.getStatus() == 2) {
                    results.add(refundPaidOrder(order.getOrderNo()));
                }
            } catch (Exception ignored) {
                // 跳过错误条目，继续处理剩余
            }
        }
        return results;
    }

    private OrderResponse toResponse(OrderInfo order, List<OrderItem> items) {
        List<OrderItemDTO> itemDTOs = items.stream()
                .map(i -> OrderItemDTO.builder()
                        .ticketId(i.getTicket().getId())
                        .price(i.getPrice())
                        .build())
                .collect(Collectors.toList());
        return OrderResponse.builder()
                .orderNo(order.getOrderNo())
                .userId(order.getUser().getId())
                .eventId(order.getEvent().getId())
                .totalAmount(order.getTotalAmount())
                .ticketCount(order.getTicketCount())
                .status(order.getStatus())
                .paymentMethod(order.getPaymentMethod())
                .paymentTime(order.getPaymentTime())
                .contactName(order.getContactName())
                .contactPhone(order.getContactPhone())
                .contactEmail(order.getContactEmail())
                .createdAt(order.getCreatedAt())
                .items(itemDTOs)
                .build();
    }

    private String generateOrderNo() {
        long ts = System.currentTimeMillis();
        int rnd = new Random().nextInt(9000) + 1000;
        return String.valueOf(ts).substring(6) + rnd; // 简单生成，长度约10-12位
    }
}